%option caseless noyywrap yylineno
%{
#include <iostream>
#include <cstring>
#include "../ast/ast.h"
typedef enum { typeKeyword, typeSymbol, typeComment } TokenType;
#include "../parser/parser.hpp"
extern void yyerror(char* s);
int offset = 1;


%}

/* declaration of substitutions */
/* definition list for keyword. reference: https://wiki.freepascal.org/Identifiers/zh_CN */
AND and
ARRAY array
BEGINN begin
CASE case
CONST const

KEYWORD_DIV div
DO do
DOWNTO downto
ELSE else
END end
FOR for
FUNCTION function
IF if
KEYWORD_MOD mod
NOT not
OF of
OR or
PROCEDURE procedure
PROGRAM program
RECORD record
REPEAT repeat
THEN then
TO to
TYPE type
UNTIL until
VAR var
WHILE while

/* definition of pascal type */
TYPE_INTEGER integer
TYPE_REAL real
TYPE_CHAR char
TYPE_BOOLEAN boolean

/* definition of literal */
LITERAL_INTEGER [0-9]+
LITERAL_REAL ([0-9]+\.[0-9]+)
LITERAL_CHAR \'..*\'
LITERAL_BOOLEAN_TRUE true
LITERAL_BOOLEAN_FALSE false

/* definition of symbol */
/* arithmetic operation */
ADD "+"
SUB "-"
MUL "*"
DIV "/"
MOD "%"
ASSIGN ":="
GT ">"
LT "<"
GE ">="
LE "<="
EQUAL "="
NEQUAL "<>"
/* addressing operation */
DOT "."
/* delimiter */
COMMA ","
SEMICOLON ";"
COLON ":"
LPAREN "("
RPAREN ")"
LBRACK "["
RBRACK "]"

/* definition of identifier */
IDENTIFIER [a-zA-Z_][a-zA-Z0-9_]*

/* definition of comment */
COMMENT "{"[^\}]*"}"

/* lexical rule */
%%
{AND} { yylval.token_type = typeKeyword; return(AND); }
{ARRAY} { yylval.token_type = typeKeyword; return(ARRAY); }
{BEGINN} { yylval.token_type = typeKeyword; return(BEGINN); }
{CASE} { yylval.token_type = typeKeyword; return(CASE); }
{CONST} { yylval.token_type = typeKeyword; return(CONST); }      
{KEYWORD_DIV} { yylval.token_type = typeKeyword; return(KEYWORD_DIV); }
{DO} { yylval.token_type = typeKeyword; return(DO); }
{DOWNTO} { yylval.token_type = typeKeyword; return(DOWNTO); }
{ELSE} { yylval.token_type = typeKeyword; return(ELSE); }
{END} { yylval.token_type = typeKeyword; return(END); }
{FOR} { yylval.token_type = typeKeyword; return(FOR); }
{FUNCTION} { yylval.token_type = typeKeyword; return(FUNCTION); }
{IF} { yylval.token_type = typeKeyword; return(IF); }
{KEYWORD_MOD} { yylval.token_type = typeKeyword; return(KEYWORD_MOD); }
{NOT} { yylval.token_type = typeKeyword; return(NOT); }
{OF} { yylval.token_type = typeKeyword; return(OF); }
{OR} { yylval.token_type = typeKeyword; return(OR); }
{PROCEDURE} { yylval.token_type = typeKeyword; return(PROCEDURE); }
{PROGRAM} { yylval.token_type = typeKeyword; return(PROGRAM); }
{RECORD} { yylval.token_type = typeKeyword; return(RECORD); }     
{REPEAT} { yylval.token_type = typeKeyword; return(REPEAT); }
{THEN} { yylval.token_type = typeKeyword; return(THEN); }
{TO} { yylval.token_type = typeKeyword; return(TO); }
{TYPE} { yylval.token_type = typeKeyword; return(TYPE); }
{UNTIL} { yylval.token_type = typeKeyword; return(UNTIL); }
{VAR} { yylval.token_type = typeKeyword; return(VAR); }
{WHILE} { yylval.token_type = typeKeyword; return(WHILE); }
{TYPE_INTEGER} { yylval.token_type = typeKeyword; return(TYPE_INTEGER); }
{TYPE_REAL} { yylval.token_type = typeKeyword; return(TYPE_REAL); }
{TYPE_CHAR} { yylval.token_type = typeKeyword; return(TYPE_CHAR); }
{TYPE_BOOLEAN} { yylval.token_type = typeKeyword; return(TYPE_BOOLEAN); }
{LITERAL_INTEGER} { yylval.string = strdup(yytext); return(LITERAL_INTEGER); }
{LITERAL_REAL} { yylval.string = strdup(yytext); return(LITERAL_REAL); }
{LITERAL_CHAR} { yylval.string = strdup(yytext); return(LITERAL_CHAR); }
{LITERAL_BOOLEAN_TRUE} { yylval.string = strdup(yytext); return(LITERAL_BOOLEAN_TRUE); }    
{LITERAL_BOOLEAN_FALSE} { yylval.string = strdup(yytext); return(LITERAL_BOOLEAN_FALSE); }  
{ADD} {  yylval.token_type = typeSymbol; return(ADD); }
{SUB} { yylval.token_type = typeSymbol; return(SUB); }
{MUL} { yylval.token_type = typeSymbol; return(MUL); }
{ASSIGN} { yylval.token_type = typeSymbol; return(ASSIGN); }
{GT} { yylval.token_type = typeSymbol; return(GT); }
{LT} { yylval.token_type = typeSymbol; return(LT); }
{GE} { yylval.token_type = typeSymbol; return(GE); }
{LE} { yylval.token_type = typeSymbol; return(LE); }
{EQUAL} { yylval.token_type = typeSymbol; return(EQUAL); }
{NEQUAL} { yylval.token_type = typeSymbol; return(NEQUAL); }
{DOT} { yylval.token_type = typeSymbol; return(DOT); }
{COMMA} { yylval.token_type = typeSymbol; return(COMMA); }
{SEMICOLON} { yylval.token_type = typeSymbol; return(SEMICOLON); }
{COLON} { yylval.token_type = typeSymbol; return(COLON); }
{LPAREN} { yylval.token_type = typeSymbol; return(LPAREN); }
{RPAREN} { yylval.token_type = typeSymbol; return(RPAREN); }
{LBRACK} { yylval.token_type = typeSymbol; return(LBRACK); }
{RBRACK} { yylval.token_type = typeSymbol; return(RBRACK); }
{IDENTIFIER} { yylval.string = strdup(yytext); return(IDENTIFIER); }
{COMMENT} { }
\n|(\r\n) { offset = 1; }
" "|\t {}
. { printf("unknown token\n"); }
%%
